package com.ktjy.gateway.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * LoggerGlobalFilter 日志全局过滤器
 * 该过滤器的优先级，越小优先级越高（注意：该系统-1表示最先执行，其他过滤器在全局过滤器的后面）
 * 用于记录请求日志，包括请求路径、请求参数、请求时间、响应时间、响应状态码、响应数据等信息
 * 可以用于监控系统性能、记录请求日志、记录异常日志等
 *
 * @author LILIBO
 * @since 2025-06-11
 */
@Slf4j
@Component
public class LoggerGlobalFilter implements GlobalFilter, Ordered {

    private static final String RESPONSE_BODY_KEY = "responseBody";

    /**
     * 重写过滤方法
     *
     * @param exchange 请求和响应的上下文
     * @param chain 过滤器链
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        long start = System.currentTimeMillis(); // 请求开始时间
        // MultiValueMap<String, String> queryParams = request.getQueryParams();
        // 请求开始，记录 <Gateway> <-- [时间戳] (请求方式) 请求路径 - 请求参数
        // log.info("<Gateway> <-- [{}] ({}) {} - {}", start, request.getMethod(), request.getURI(), (queryParams.isEmpty() ? request.getBody().toString() : queryParams + " " + request.getBody().toString()));
        log.info("<Gateway> <-- [{}] ({}) {}", start, request.getMethod(), request.getURI());
        // -------- 以上是前置逻辑 --------

        // 注意：doFinally方法是在响应结束后执行的，所以可以获取到响应状态码和响应数据
        return chain.filter(exchange).doFinally(result -> {
            // -------- 以下是后置逻辑 --------
            long end = System.currentTimeMillis(); // 响应结束时间
            // 记录响应体
            // Object responseBody = exchange.getAttribute(RESPONSE_BODY_KEY);
            // 响应结束，记录 <Gateway> --> [时间戳] (响应时长) 响应状态码 - 响应数据
            // log.info("<Gateway> --> [{}] ({}) {} - {}", start, (end - start), response.getStatusCode(), responseBody);
            log.info("<Gateway> --> [{}] ({}) {}", start, (end - start), response.getStatusCode());
        });
    }

    @Override
    public int getOrder() {
        // 该系统-1表示最先执行，其他过滤器在全局过滤器的后面
        return -1;
    }

}
